#include <benchmark/benchmark.h>

#include <pthread.h>
#include "util.h"

static void Bm_function_pthread_mutex_trylock_fast(benchmark::State &state)
{
    pthread_mutexattr_t mutex_attr;
    pthread_mutexattr_init(&mutex_attr);
    pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);

    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, &mutex_attr);

    while (state.KeepRunning()) {
        pthread_mutex_trylock(&mutex);
        pthread_mutex_unlock(&mutex);
    }
}

MUSL_BENCHMARK(Bm_function_pthread_mutex_trylock_fast);

static void Bm_function_pthread_mutex_trylock_errchk(benchmark::State &state)
{
    pthread_mutexattr_t mutex_attr;
    pthread_mutexattr_init(&mutex_attr);
    pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);

    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, &mutex_attr);
    while (state.KeepRunning()) {
        pthread_mutex_trylock(&mutex);
        pthread_mutex_unlock(&mutex);
    }
}

MUSL_BENCHMARK(Bm_function_pthread_mutex_trylock_errchk);

static void Bm_function_pthread_mutex_trylock_rec(benchmark::State &state)
{
    pthread_mutexattr_t mutex_attr;
    pthread_mutexattr_init(&mutex_attr);
    pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);

    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, &mutex_attr);

    while (state.KeepRunning()) {
        pthread_mutex_trylock(&mutex);
        pthread_mutex_unlock(&mutex);
    }
}

MUSL_BENCHMARK(Bm_function_pthread_mutex_trylock_rec);


static void Bm_function_pthread_mutex_timedlock_fast(benchmark::State &state)
{
    struct timespec ts = {.tv_sec = 1, .tv_nsec = 0};

    pthread_mutexattr_t mutex_attr;
    pthread_mutexattr_init(&mutex_attr);
    pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);

    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, &mutex_attr);

    while (state.KeepRunning()) {
        pthread_mutex_timedlock(&mutex, &ts);
        pthread_mutex_unlock(&mutex);
    }
}

MUSL_BENCHMARK(Bm_function_pthread_mutex_timedlock_fast);

static void Bm_function_pthread_mutex_timedlock_errchk(benchmark::State &state)
{
    struct timespec ts = {.tv_sec = 1, .tv_nsec = 0};

    pthread_mutexattr_t mutex_attr;
    pthread_mutexattr_init(&mutex_attr);
    pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);

    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, &mutex_attr);

    while (state.KeepRunning()) {
        pthread_mutex_timedlock(&mutex, &ts);
        pthread_mutex_unlock(&mutex);
    }
}

MUSL_BENCHMARK(Bm_function_pthread_mutex_timedlock_errchk);

static void Bm_function_pthread_mutex_timedlock_rec(benchmark::State &state)
{
    struct timespec ts = {.tv_sec = 1, .tv_nsec = 0};

    pthread_mutexattr_t mutex_attr;
    pthread_mutexattr_init(&mutex_attr);
    pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);

    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, &mutex_attr);

    while (state.KeepRunning()) {
        pthread_mutex_timedlock(&mutex, &ts);
        pthread_mutex_unlock(&mutex);
    }
}

MUSL_BENCHMARK(Bm_function_pthread_mutex_timedlock_rec);


static void Bm_function_pthread_rwlock_tryrdlock(benchmark::State &state)
{
    pthread_rwlock_t rwlock;
    pthread_rwlock_init(&rwlock, nullptr);
    while (state.KeepRunning()) {
        pthread_rwlock_tryrdlock(&rwlock);
        pthread_rwlock_unlock(&rwlock);
    }
    pthread_rwlock_destroy(&rwlock);
}

MUSL_BENCHMARK(Bm_function_pthread_rwlock_tryrdlock);